/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package plan;

import com.homesoft.util.DateTime;
import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.MouseAdapter;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Locale;
import java.util.TimeZone;
import javax.swing.DefaultListSelectionModel;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.table.DefaultTableModel;
import org.jdesktop.swingx.JXDatePicker;
import org.jdesktop.swingx.JXTable;

/**
 *
 * @author phucan
 */
public class Planner extends JPanel implements Serializable {

    JXTable gridView;
    JLabel lblDateRange;
    //JXTable grid2;
    DefaultTableModel model;
    Calendar c = Calendar.getInstance();
    ArrayList<Event> events;
    HashMap<Integer, EventType> eventTypeList;
    TextBoxRender render;
    int[][] indexArray;
    PlannerDataAccess pda;
    Date start;
    Date end;
    int currentX;
    int currentY;
    int PERIOD_COUNT = 60;
    String[][] data = new String[PERIOD_COUNT][8];
    JXDatePicker dpkDate;

    public Planner(Date d, PlannerDataAccess pda, ArrayList<EventType> eTypes) {
        String[] cols = new String[]{"", "Th.2", "Th.3", "Th.4", "Th.5", "Th.6", "Th.7", "CN"};

        indexArray = new int[PERIOD_COUNT][8];
        for (int i = 0; i < PERIOD_COUNT; i++) {
            for (int j = 0; j < 8; j++) {
                if (j == 0) {
                    data[i][j] = 6 + i / 4 + ":" + String.format("%02d", (i % 4) * 15);
                } else {
                    data[i][j] = "";
                }
                indexArray[i][j] = -1;
            }
        }
        eventTypeList = new HashMap<>();
        for (EventType et : eTypes) {
            eventTypeList.put(et.getId(), et);
        }
        this.pda = pda;
        c.setTime(d);
        c.setFirstDayOfWeek(Calendar.SUNDAY);
        render = new TextBoxRender(eventTypeList, PERIOD_COUNT);
        //   render.setMark(1, 1, 1);
//        render.setMark(2, 2, 1);
//        render.setMark(2, 5, 2);

        RowHeader rh = new RowHeader();
        //rh.setEnabled(false);
        gridView = new JXTable();
        gridView.setEditable(false);
        gridView.setSortable(false);
        //gridView.setDefaultRenderer(String.class, new TextBoxRender());

        model = new DefaultTableModel(data, cols);
        gridView.setModel(model);

        gridView.setDefaultRenderer(Object.class, render);
        gridView.getColumn(0).setCellRenderer(rh);
        gridView.getColumn(0).setPreferredWidth(60);
        gridView.getColumn(0).setMaxWidth(60);
        gridView.getColumn(0).setMinWidth(60);
        gridView.setRowHeight(25);
        gridView.setFont(gridView.getFont().deriveFont(15));
        gridView.setSelectionMode(DefaultListSelectionModel.SINGLE_SELECTION);
        JScrollPane scrollPane = new JScrollPane(gridView);

        //navigator
        JPanel pnlNavigator = new JPanel(new FlowLayout(FlowLayout.LEFT));
        dpkDate = new JXDatePicker(new Locale("vi", "VN"));
        dpkDate.setFormats("dd/MM/yyyy");
        dpkDate.setDate(d);
        JButton btnPre = new JButton(" Tuần Trước");
        JButton btnNxt = new JButton(" Tuần Sau");
        JLabel lblDate = new JLabel("Ngày");
        JLabel lblWeek = new JLabel("Tuần");
        lblDateRange = new JLabel();
        lblDateRange.setFont(lblDateRange.getFont().deriveFont(18));

        this.setLayout(new BorderLayout());
        this.add(pnlNavigator, BorderLayout.NORTH);
        this.add(scrollPane, BorderLayout.CENTER);
        pnlNavigator.add(lblDate);
        pnlNavigator.add(dpkDate);
        pnlNavigator.add(lblWeek);
        pnlNavigator.add(btnPre);
        pnlNavigator.add(btnNxt);
        pnlNavigator.add(lblDateRange);
//action
        btnPre.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                previousWeek();
            }
        });
        btnNxt.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                nextWeek();
            }
        });
        dpkDate.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                if (dpkDate.getDate() != null) {
                    setDate(dpkDate.getDate());
                    refresh();
                }
            }
        });
        goToWeek(curWeek);
    }

    public Planner() {
        this(new Date(), null, null);
    }

    public Date getDateOfWeek(int year, int woy, int dayOfWeek) {
        c.setWeekDate(year, woy, dayOfWeek);
        c.setTimeZone(TimeZone.getDefault());
        c.set(Calendar.HOUR, 1);
        return c.getTime();
    }

    public void translateCellAddress(int hour, int minute) {
        currentY = hour + minute / 15;
        currentX = c.get(Calendar.DAY_OF_WEEK) != Calendar.SUNDAY ? c.get(Calendar.DAY_OF_WEEK) - 1 : 7;
    }

//    public void addEvent(Date date, int hour, int minute, String shortContent, int eventType) {
//        c.setTime(date);
//        translateCellAddress(hour, minute);
//        //Eve
//    }
    public void addEvent(Event e) {
        setDate(e.getDate());
        translateCellAddress(e.getHour(), e.getMinute());
        events.add(e);
        indexArray[currentY][currentX] = events.indexOf(e);
        render.setMark(currentY, currentX, e.getType().getId());
        //pan edit
        updateWeekDateRange(curWeek);
        //fetchEventsFromDb(start, end);
        loadEvents();
        refresh();
    }

    public Event getSelectedEvent() {
        updateXYWithMouse();
        if (indexArray[currentX][currentY] == -1) {
            return null;
        }
        return events.get(indexArray[currentX][currentY]);
    }

    public void deleteSelectedEvent() {
        updateXYWithMouse(); //allow edit
        gridView.setEditable(true);
        render.setMark(currentX, currentY, -1);
        events.remove(indexArray[currentX][currentY]);
        indexArray[currentX][currentY] = -1;
        gridView.setValueAt("", currentX, currentY);
        gridView.setEditable(false); //prevent edit
    }

    public void deleteWeekEvent() {
        for (int i = 0; i < PERIOD_COUNT; i++) {
            for (int j = 1; j < 8; j++) {
                render.setMark(i, j, 0);
                indexArray[i][j] = -1;
            }
        }
        events.clear();
    }

    public boolean editEvent(Event e) {
        //updateXYWithMouse();
        int size = events.size();
        for (int i = 0; i < size; i++) {
            if (events.get(i).getId() == e.getId()) {
                events.set(i, e);
                break;
            }
        }
        return true;
    }

    public void addEventType(EventType type) {
        eventTypeList.put(type.getId(), type);
    }

    public void addMouseListenerOnGrid(MouseAdapter evt) {
        gridView.addMouseListener(evt);
    }

    public void addKeyListenerOnGrid(KeyAdapter evt) {
        gridView.addKeyListener(evt);
    }

    private PlanElement TimeToXY(Date date, int hour, int minute) {
        c.setTime(date);
        int x = ((hour >= 6 ? hour : (hour + 12)) - 6) * 4 + minute / 15;
        int y = c.get(Calendar.DAY_OF_WEEK) != Calendar.SUNDAY ? c.get(Calendar.DAY_OF_WEEK) - 1 : 7;
        PlanElement et = new PlanElement(x, y);
        return et;
    }

    private Date XYToTime(int x, int y) {
        int dow = x;
        int hour = y / 4;
        int min = 15 * (y % 4);
        c.set(Calendar.DAY_OF_WEEK, x == 7 ? 1 : x + 1);
        c.set(Calendar.HOUR_OF_DAY, hour);
        c.set(Calendar.MINUTE, min);
        //Date d=c.getTime();
        return c.getTime();
    }
    int curWeek = c.get(Calendar.WEEK_OF_YEAR);

    private void nextWeek() {
        DateTime dt = new DateTime(c.getTime());

        curWeek++;

        dt = dt.addDay(7);
        c.setTime(dt.getDateTime());
        dpkDate.setDate(dt.getDateTime());
        //c.set(c.get(Calendar.YEAR),c.get(Calendar.MONTH), c.get(Calendar.DAY_OF_MONTH));
        //c.setWeekDate(c.get(Calendar.YEAR),curWeek, c.get(Calendar.DAY_OF_WEEK));
        updateWeekDateRange(curWeek);
        fetchEventsFromDb(start, end);
        loadEvents();
        // updatePlanUI();
        // }
    }

    private void previousWeek() {
        DateTime dt = new DateTime(c.getTime());
        curWeek--;

        dt = dt.addDay(-7);
        c.setTime(dt.getDateTime());
        dpkDate.setDate(dt.getDateTime()); //c.setWeekDate(c.get(Calendar.YEAR),curWeek, c.get(Calendar.DAY_OF_WEEK));
        updateWeekDateRange(curWeek);
        fetchEventsFromDb(start, end);
        loadEvents();
        // updatePlanUI();
        //  }
    }

    private void goToWeek(int week) {
        //if (week > 0 && week <= c.getWeeksInWeekYear()) {
        c.set(Calendar.WEEK_OF_YEAR, week);
        updateWeekDateRange(week);
        DateTime dt1 = new DateTime(start);
        //DateTime dt2=new DateTime(end);        
        fetchEventsFromDb(start, end);
        loadEvents();
        //}
    }

    private void updateWeekDateRange(int week) {
        start = getDateOfWeek(c.get(Calendar.YEAR), week, Calendar.MONDAY);
        end = getDateOfWeek(c.get(Calendar.YEAR), week + 1, Calendar.SUNDAY);
        start = new DateTime(start, DateTime.DATE).getDateTime();
        end = new DateTime(end, DateTime.DATE).getDateTime();
        end = new DateTime(end).addHour(23).addMinute(59).addSecond(59).getDateTime();

    }

    private void updateXYWithMouse() {
        currentY = gridView.getSelectedColumn();
        currentX = gridView.getSelectedRow();
        if (currentX < 0 || currentY < 0) {
            currentX = 0;
            currentY = 0;
        }
    }

    private void loadEvents() {
        gridView.setEditable(true); //allow edit
        for (int i = 0; i < PERIOD_COUNT; i++) {
            for (int j = 0; j < 8; j++) {
                if (j > 0) {
                    gridView.setValueAt("", i, j);
                }
                indexArray[i][j] = -1;
                render.setMark(i, j, 0);
            }
        }
        for (Event e : events) {
            PlanElement pe = TimeToXY(e.getDate(), e.hour, e.getMinute());
            indexArray[pe.x][pe.y] = events.indexOf(e);
            render.setMark(pe.x, pe.y, e.getType().getId());

            gridView.setValueAt(e.getShortContent(), pe.x, pe.y);

        }
        gridView.setEditable(false); //prevent edit
//        for (int i = 0; i < 48; i++) {
//            for (int j = 1; j < 8; j++) {
        //if (indexArray[i][j] > 0) {
        //  PlanElement pe=TimeToXY(events.get(i), j, i)
//                    gridView.setValueAt(events.get(indexArray[i][j]), i, j);
//                    render.setMark(i,j,events.get(indexArray[i][j]).getType().getId());
        //}
        //     }
        // }
        /*up date grid header*/
        DateTime day = new DateTime(start);
        for (int i = 1; i < 7; i++) {
            gridView.getColumn(i).setHeaderValue(String.format("Th.%d (%d/%d)", i + 1, day.addDay(i - 1).getDay(), day.getMonth()));
        }
        gridView.getColumn(7).setHeaderValue(String.format("CN (%d/%d)", day.addDay(6).getDay(), day.getMonth()));
        lblDateRange.setText("<html>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Từ <b>" + DateTime.getAsString(start) + "</b> đến <b>" + DateTime.getAsString(end) + "</b></html>");
    }

    private void fetchEventsFromDb(Date start, Date end) {
        if (pda != null) {
            events = pda.fetchEvents(start, end);
        } else {
            throw new NullPointerException("Home: DataAccess object is null");
        }
    }

//    private void updatePlanUI() {
//        gridView.setDefaultRenderer(Object.class, render);
//
//        gridView.setModel(model);
//        gridView.updateUI();
//    }
    public void setDate(Date d) {
        c = Calendar.getInstance();
        c.setTime(d);
        curWeek = c.get(Calendar.WEEK_OF_YEAR);
    }

    public void refresh() {

        curWeek = c.get(Calendar.WEEK_OF_YEAR);
        //DateTime dt = new DateTime(new Date(), DateTime.DATE);     

        updateWeekDateRange(curWeek);

        fetchEventsFromDb(start, end);
        loadEvents();
    }
}
